﻿using System;
using System.Text;
using Up2Link.Core;

namespace Up2Link.ArgArray
{
    /// <summary>
    /// 类库提供的简单消息类
    /// </summary>
    public class CMessageAA : IMessage
    {
        private Int16 messageCode = 0;          //消息码，2字节
        public Int16 MsgCode
        {
            get { return messageCode; }
        }

        private String source = "";             //消息发送源，长度可变
        public String Source
        {
            get { return source; }
        }

        private String[] arguments = null;      //消息参数数组，长度可变
        public String[] Arguments
        {
            get { return arguments; }
        }

        //空的无参数构造函数
        public CMessageAA()
        {
        }

        //使用字符串作为参数的构造函数
        //注意字符串至少要包含一个空格，且第一个空格前的内容必须是一个整数
        //否则程序会出错
        //示例：new CMessageAA("0 server abc")
        public CMessageAA(String str)
        {
            Char[] sep = new Char[1];
            sep[0] = ' ';
            String[] tokens = str.Split(sep);
            messageCode = Int16.Parse(tokens[0]);
            source = tokens[1];
            if (tokens.Length > 2)
            {
                arguments = new String[tokens.Length - 2];
                for (Int32 i = 0; i < tokens.Length - 2; i++)
                {
                    arguments[i] = tokens[2 + i];
                }
            }
        }

        //直接使用消息的各个部分作为参数的构造函数
        public CMessageAA(Int16 messageCode, String source, String[] arguments)
        {
            this.messageCode = messageCode;
            this.source = source;
            this.arguments = arguments;
        }

        //使用字节数组作为参数的构造函数
        public CMessageAA(Byte[] msgBytes)
        {
            this.Decode(msgBytes);
        }

        //实现IMessage接口必须的函数
        //将字节数组解码为消息的各个部分
        //ArgArray消息的具体格式为：
        //4字节的消息总长度
        //2字节的消息码
        //2字节的消息来源长度
        //不定长度的消息来源信息
        //2字节的参数个数信息
        //每个参数先是2字节的参数长度，之后跟着是不定长度的参数内容
        public void Decode(Byte[] msgBytes)
        {
            messageCode = BitConverter.ToInt16(msgBytes, 4);

            Int16 sourceLength = BitConverter.ToInt16(msgBytes, 6);
            source = Encoding.UTF32.GetString(msgBytes, 8, sourceLength);

            Int16 argNum = BitConverter.ToInt16(msgBytes, 8 + sourceLength);
            Int16[] argLenList = new Int16[argNum];
            arguments = new String[argNum];
            Int16 accuLength = 0;
            for (Int32 i = 0; i < argNum; i++)
            {
                argLenList[i] = BitConverter.ToInt16(msgBytes, 10 + sourceLength + i * 2);
                arguments[i] = Encoding.UTF32.GetString(msgBytes, 10 + sourceLength + argNum * 2 + accuLength, argLenList[i]);
                accuLength += (Int16)(argLenList[i]);
            }
        }

        //将消息转化成简单的字符串
        public override String ToString()
        {
            StringBuilder sb = new StringBuilder();
            if (source != "")
            {
                sb.Append("来自 " + source);
            }
            else
            {
                sb.Append("来自未知消息源");
            }
            sb.Append(" 消息码 " + messageCode.ToString() + " 参数");
            for (Int32 i = 0; i < arguments.Length; i++)
            {
                sb.Append(" " + arguments[i]);
            }

            return sb.ToString();
        }

        //以字符串形式返回消息的参数部分
        public String GetContent()
        {
            if (arguments != null)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(arguments[0]);
                for (Int32 i = 1; i < arguments.Length; i++)
                {
                    sb.Append(" " + arguments[i]);
                }
                return sb.ToString();
            }
            else
            {
                return null;
            }
        }

        //以字符串形式返回消息的第一个参数
        public String GetContentHead()
        {
            if (arguments != null)
            {
                return arguments[0];
            }
            else
            {
                return null;
            }
        }

        //以字符串形式返回消息除去第一个参数以后剩下的所有参数
        public String GetContentTail()
        {
            if (arguments != null && arguments.Length > 1)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(arguments[1]);
                for (Int32 i = 2; i < arguments.Length; i++)
                {
                    sb.Append(" " + arguments[i]);
                }
                return sb.ToString();
            }
            else
            {
                return null;
            }
        }

        //返回消息的参数个数
        public Int32 GetContentLength()
        {
            if (arguments != null)
            {
                return arguments.Length;
            }
            else
            {
                return 0;
            }
        }

        //实现IMessage接口必须的函数
        //将消息编码为字节数组
        //ArgArray消息的具体格式参见Decode函数的注释
        public Byte[] Encode()
        {
            //先将各部分转化成字节数组，便于之后计算消息长度
            Byte[] codeBytes = BitConverter.GetBytes(messageCode);
            Byte[] sourceBytes = Encoding.UTF32.GetBytes(source);
            Byte[] sourceLenBytes = BitConverter.GetBytes((Int16)sourceBytes.Length);

            Byte[] argNumBytes = null;
            Byte[] argLenListBytes = null;
            Byte[] argBytes = null;

            Byte[] msgBytes = null;

            if (arguments != null)
            {
                argNumBytes = BitConverter.GetBytes((Int16)arguments.Length);
                argLenListBytes = new Byte[arguments.Length * 2];
                for (Int32 i = 0; i < arguments.Length; i++)
                {
                    BitConverter.GetBytes((Int16)(arguments[i].Length * 4)).CopyTo(argLenListBytes, i * 2);
                    Byte[] tempBytes = null;
                    if (argBytes != null)
                    {
                        tempBytes = new Byte[argBytes.Length + arguments[i].Length * 4];
                        argBytes.CopyTo(tempBytes, 0);
                        Encoding.UTF32.GetBytes(arguments[i]).CopyTo(tempBytes, argBytes.Length);
                    }
                    else
                    {
                        tempBytes = new Byte[arguments[i].Length * 4];
                        Encoding.UTF32.GetBytes(arguments[i]).CopyTo(tempBytes, 0);
                    }
                    argBytes = tempBytes;
                }

                Int32 msgLength = 10 + sourceBytes.Length + argLenListBytes.Length + argBytes.Length;
                msgBytes = new Byte[msgLength];
                BitConverter.GetBytes(msgLength).CopyTo(msgBytes, 0);
                codeBytes.CopyTo(msgBytes, 4);
                sourceLenBytes.CopyTo(msgBytes, 6);
                sourceBytes.CopyTo(msgBytes, 8);
                argNumBytes.CopyTo(msgBytes, 8 + sourceBytes.Length);
                argLenListBytes.CopyTo(msgBytes, 10 + sourceBytes.Length);
                argBytes.CopyTo(msgBytes, 10 + sourceBytes.Length + argLenListBytes.Length);
            }
            else
            {
                argNumBytes = BitConverter.GetBytes((Int16)0);
                Int32 msgLength = 10 + sourceBytes.Length;
                msgBytes = new Byte[msgLength];
                BitConverter.GetBytes(msgLength).CopyTo(msgBytes, 0);
                codeBytes.CopyTo(msgBytes, 4);
                sourceLenBytes.CopyTo(msgBytes, 6);
                sourceBytes.CopyTo(msgBytes, 8);
                argNumBytes.CopyTo(msgBytes, 8 + sourceBytes.Length);
            }

            return msgBytes;
        }
    }
}
